using System;
using System.Collections.Generic;
using System.Text;
using System.CodeDom;

namespace SharpMud.Text.Dynamic.Processing
{
    /// <summary>
    /// Represents a singular processed chunk of a Dynamic Text Body
    /// </summary>
    public interface INugget
    {
        /// <summary>
        /// Converts this Dynamic Text nugget to the form it would occur in an unprocessed
        /// Dynamic Text Body
        /// </summary>
        string ToUnprocessedText();

        /// <summary>
        /// The line number and "filename" of the original Dynamic Text Body that this INugget occurs at
        /// </summary>
        CodeLinePragma CodeLinePragma { get;}
    }

    /// <summary>
    /// Represents a chunk of a DTB that specifies code generation and code compiling options
    /// for the DTB
    /// </summary>
    public class MetacommandNugget : INugget, IMetacommand
    {
        private string _Name;
        private IList<KeyValuePair<string, string>> _Parameters;
        private CodeLinePragma _CodeLinePragma;

        private MetacommandNugget() { }
        public MetacommandNugget(string name, IList<KeyValuePair<string, string>> parameters, CodeLinePragma codeLinePragma)
        {
            _Name = name;
            _Parameters = parameters;
            _CodeLinePragma = codeLinePragma;
        }
        public string Name
        {
            get
            {
                return _Name;
            }
        }

        public IList<KeyValuePair<string,string>> Parameters
        {
            get
            {
                return _Parameters;
            }
        }

        #region INugget Members

        public string ToUnprocessedText()
        {
            System.Text.StringBuilder sb = new StringBuilder();

            sb.AppendFormat("<%@ {0}", this.Name);

            foreach (KeyValuePair<string,string> kvp in this._Parameters)
            {
                sb.AppendFormat(" {0}=\"{1}\"", kvp.Key, kvp.Value);
            }

            sb.Append(" %>");
            return sb.ToString();
        }

        public CodeLinePragma CodeLinePragma
        {
            get
            {
                return _CodeLinePragma;
            }
        }
        #endregion

        #region IMetacommand Members

        string IMetacommand.Name
        {
            get { return this._Name; }
        }

        IList<KeyValuePair<string, string>> IMetacommand.Parameters
        {
            get { return this._Parameters; }
        }

        #endregion

        public static MetacommandNugget FromMetacommand(IMetacommand metacommand)
        {
            return FromMetacommand(metacommand, null);
        }
        public static MetacommandNugget FromMetacommand(IMetacommand metacommand, CodeLinePragma codeLinePragma)
        {
            return new MetacommandNugget(metacommand.Name, metacommand.Parameters, codeLinePragma);
        }
    }

    /// <summary>
    /// Represents a chunk of a DTB that is raw, static text
    /// </summary>
    public class RawTextNugget : INugget
    {
        private string _StaticText;
        private CodeLinePragma _CodeLinePragma;
        
        private RawTextNugget() { }
        public RawTextNugget(string staticText, CodeLinePragma codeLinePragma)
        {
            _StaticText = staticText;
            _CodeLinePragma = codeLinePragma;
        }
        public string StaticText
        {
            get
            {
                return _StaticText;
            }
        }

        public CodeExpression ToCodeExpression()
        {
            CodePrimitiveExpression cpe = new CodePrimitiveExpression(StaticText);
            
            return cpe;
        }
        public CodeStatement ToCodeStatement(CodeExpression writeObject, string writeMethodName)
        {
            CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(writeObject, writeMethodName, ToCodeExpression());
            CodeExpressionStatement ces = new CodeExpressionStatement(cmie);
            ces.LinePragma = this._CodeLinePragma;
            return ces;
        }

        #region INugget Members

        public string ToUnprocessedText()
        {
            return StaticText;
        }

        public CodeLinePragma CodeLinePragma
        {
            get
            {
                return _CodeLinePragma;
            }
        }
        #endregion
    }

    /// <summary>
    /// Represents a chunk of a DTB that is pure code
    /// </summary>
    public class RawCodeNugget : INugget
    {
        private System.Type _CodeDomProvider;
        private string _CodeContents;
        private CodeLinePragma _CodeLinePragma;
        
        private RawCodeNugget() { }
        public RawCodeNugget(System.Type codeDomProvider, string codeContents, CodeLinePragma codeLinePragma)
        {
            _CodeDomProvider = codeDomProvider;
            _CodeContents = codeContents;
            _CodeLinePragma = codeLinePragma;
        }

        public System.Type CodeDomProvider
        {
            get
            {
                return _CodeDomProvider;
            }
        }

        public string CodeContents
        {
            get
            {
                return _CodeContents;
            }
        }

        public LanguageBoundCode<CodeSnippetStatement> ToCodeStatement()
        {
            CodeSnippetStatement css = new CodeSnippetStatement(CodeContents);
            css.LinePragma = this._CodeLinePragma;
            return new LanguageBoundCode<CodeSnippetStatement>(css, this.CodeDomProvider);
        }

        #region INugget Members

        public string ToUnprocessedText()
        {
            System.Text.StringBuilder sb = new StringBuilder();
            sb.AppendFormat("<% {0} %>", CodeContents);
            return sb.ToString();
        }
        public CodeLinePragma CodeLinePragma
        {
            get
            {
                return _CodeLinePragma;
            }
        }
        #endregion
    }

    /// <summary>
    /// Represents a chunk of DTB that is an expression that is to be evaluated and written to the text output as text is being generated
    /// </summary>
    public class TextExpressionNugget : INugget
    {
        private string _ExpressionCode;
        private System.Type _CodeDomProvider;
        private CodeLinePragma _CodeLinePragma;

        private TextExpressionNugget() { }
        public TextExpressionNugget(string expressionCode, System.Type codeDomProvider, CodeLinePragma codeLinePragma)
        {
            _ExpressionCode = expressionCode;
            _CodeDomProvider = codeDomProvider;
            _CodeLinePragma = codeLinePragma;
        }

        public string ExpressionCode
        {
            get
            {
                return _ExpressionCode;
            }
        }

        public System.Type CodeDomProvider
        {
            get
            {
                return _CodeDomProvider;
            }
        }

        public LanguageBoundCode<CodeStatement> ToCodeStatement(CodeExpression writeObject, string writeMethodName)
        {
            CodeSnippetExpression cse = new CodeSnippetExpression(this._ExpressionCode);
            CodeMethodInvokeExpression cmie = new CodeMethodInvokeExpression(writeObject, writeMethodName,cse);
            CodeExpressionStatement ces = new CodeExpressionStatement(cmie);
            ces.LinePragma = _CodeLinePragma;
            return new LanguageBoundCode<CodeStatement>(ces, _CodeDomProvider);
        }

        #region INugget Members

        public string ToUnprocessedText()
        {
            System.Text.StringBuilder sb = new StringBuilder();
            sb.AppendFormat("<%= {0} %>", this.ExpressionCode);
            return sb.ToString();
        }

        public CodeLinePragma CodeLinePragma
        {
            get { return _CodeLinePragma; }
        }

        #endregion
    }
}
